<template>
	<div ref="statsRef" class="statistics"></div>
	<div ref="containerRef" class="container"></div>
</template>

<script lang="ts" setup>
import {onMounted, ref, watch} from 'vue';
import {AxesHelper, Color, MeshBasicMaterial, PerspectiveCamera, PlaneGeometry, Scene, WebGLRenderer, Mesh, BoxGeometry, SphereGeometry, SpotLight, MeshLambertMaterial, MeshPhongMaterial, DoubleSide, PointLight, AmbientLight, CameraHelper, DirectionalLight} from 'three';
import Stats from 'stats.js';
import * as dat from 'dat.gui';

const stats = new Stats();

// stats.dom.style.top = '50px';
stats.showPanel(0);
	
const containerRef = ref<HTMLDivElement>();
const statsRef = ref<HTMLDivElement>();
const scene = new Scene();
const camera = new PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

camera.position.set(-30, 40, 30);
camera.lookAt(scene.position);

const renderer = new WebGLRenderer();

// renderer.setClearColor(new Color(0xeeeeee));
renderer.setClearColor(0xeeeeee);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;

const cubeGeometry = new BoxGeometry(4, 4, 4);

const cubeMaterial = new MeshLambertMaterial({
// const cubeMaterial = new MeshBasicMaterial({
	color: 0xff0000,
	wireframe: false,
});

const cube = new Mesh(cubeGeometry, cubeMaterial);

cube.castShadow = true;
cube.position.set(-2, 2, 6);
scene.add(cube);

/**
* 光源设置
*/
//聚光灯
const spotLight = new SpotLight(0xffffff, 1000);

spotLight.position.set(-20, 30, -10);
spotLight.castShadow = true;
scene.add(spotLight);

//平行光
const directionalLight = new DirectionalLight('#ff5808');

directionalLight.position.set(-40, 60, -10);
directionalLight.castShadow = true;
directionalLight.intensity = 0.5;
scene.add(directionalLight);

const axes = new AxesHelper(20);

scene.add(axes);

const cameraHelper = new CameraHelper(directionalLight.shadow.camera);

const planeGeometry = new PlaneGeometry(60, 20);
const meshBasicMaterial = new MeshLambertMaterial({color: 0xcccccc});
// const meshBasicMaterial = new MeshBasicMaterial({color: 0xcccccc});
const plane = new Mesh(planeGeometry, meshBasicMaterial);

plane.receiveShadow = true;
plane.rotation.x = -0.5 * Math.PI;
plane.position.x = 15;
plane.position.y = 0;
plane.position.z = 0;
scene.add(plane);

const sphereGeometry = new SphereGeometry(4);

const sphereMaterial = new MeshLambertMaterial({
// const sphereMaterial = new MeshBasicMaterial({
	color: 0x7777ff,
	wireframe: false,
});

const sphere = new Mesh(sphereGeometry, sphereMaterial);

sphere.castShadow = true;
sphere.position.x = 20;
sphere.position.y = 4;
sphere.position.z = 2;
scene.add(sphere);

const lookAtGeom = new SphereGeometry(1);

const lookAtMesh = new Mesh(lookAtGeom, new MeshLambertMaterial({
	color: 0xff0000,
}));

scene.add(lookAtMesh);

const controlRef = ref({
	rotationSpeed: 0.02,
	bouncingSpeed: 0.03,
	numberOfObjects: 0,
	ambientColor: '#0c0c0c',
	pointColor: '#ccffcc',
	distance: 100,
	intensity: 1,
	debug: false,
	target: 'plane',
	directionalColor: '#ccffcc',
	addCube: function(){
		const cubeGeometry = new BoxGeometry(4, 4, 4);
		const cube = new Mesh(cubeGeometry, cubeMaterial);
		
		cube.name = 'cube-' + scene.children.length;
		cube.castShadow = true;
		cube.position.x = -30 + Math.round(Math.random() * 60);
		cube.position.y = Math.round(Math.random() * 5);
		cube.position.z = -20 + Math.round(Math.random() * 40);
		scene.add(cube);
		this.numberOfObjects = scene.children.length;
	},
	remove: function(){
		const allChildren = scene.children;
		const lastObject = allChildren[allChildren.length - 1];
		
		if(lastObject instanceof Mesh && lastObject.name.startsWith('cube')){
			//mesh 网格模型，且名称以 cube 开头，新添加的立方体
			scene.remove(lastObject);
		}
		
		this.numberOfObjects = scene.children.length;
	},
});

const ambientLight = new AmbientLight(controlRef.value.ambientColor);

scene.add(ambientLight);

const pointLight = new PointLight(controlRef.value.pointColor, 100);

pointLight.distance = 100;
pointLight.position.copy(lookAtMesh.position);
scene.add(pointLight);

if(document.querySelectorAll('.dg.ac>.dg.main.a').length === 0){
	//还未初始化图形用户界面
	window.gui = new dat.GUI();
	window.gui.add(controlRef.value, 'rotationSpeed', 0, 0.5);
	window.gui.add(controlRef.value, 'bouncingSpeed', 0, 0.5);
	window.gui.add(controlRef.value, 'numberOfObjects').listen();
	window.gui.add(controlRef.value, 'addCube');
	window.gui.add(controlRef.value, 'remove');
	window.gui.addColor(controlRef.value, 'ambientColor');
	window.gui.add(controlRef.value, 'distance', 0, 200);
	window.gui.add(controlRef.value, 'intensity', 0, 1000);
	window.gui.addColor(controlRef.value, 'pointColor');
	window.gui.add(controlRef.value, 'debug');
	window.gui.add(controlRef.value, 'target', ['plane', 'cube', 'sphere']);
	window.gui.addColor(controlRef.value, 'directionalColor');
}

let step = 0;

function renderScene(){
	stats.update();
	
	/* scene.traverse((e) => {
		if(e.name.startsWith('cube')){
			//名称以 cube 开头，新添加的立方体
			e.rotation.x += controlRef.value.rotationSpeed;
			e.rotation.y += controlRef.value.rotationSpeed;
			e.rotation.z += controlRef.value.rotationSpeed;
		}
	});
	
	cube.rotation.x += controlRef.value.rotationSpeed;
	cube.rotation.y += controlRef.value.rotationSpeed;
	cube.rotation.z += controlRef.value.rotationSpeed;
	// cube.scale.x += 0.01;
	step += controlRef.value.bouncingSpeed;
	sphere.position.x = 20 + 10 * Math.cos(step);
	sphere.position.y = 2 + 10 * Math.abs(Math.sin(step)); */
	step += 0.1;
	
	lookAtMesh.position.set(
		20 + 10 * Math.cos(step),
		5 + 10 * Math.abs(Math.sin(step)),
		10 * Math.cos(step)
	);
	
	spotLight.position.copy(lookAtMesh.position);
	requestAnimationFrame(renderScene);
	renderer.render(scene, camera);
}

renderScene();

watch(
	() => controlRef.value.ambientColor,
	(n) => {
		ambientLight.color = new Color(n);
	}
);

watch(
	() => controlRef.value.pointColor,
	(n) => {
		pointLight.color = new Color(n);
	}
);

watch(
	() => controlRef.value.directionalColor,
	(n) => {
		directionalLight.color = new Color(n);
	}
);

watch(
	() => controlRef.value.distance,
	(n) => {
		spotLight.distance = n;
	}
);

watch(
	() => controlRef.value.intensity,
	(n) => {
		spotLight.intensity = n;
	}
);

watch(
	() => controlRef.value.debug,
	(n) => {
		if(n){
			//显示平行光辅助对象
			scene.add(cameraHelper);
		}else{
			//不显示平行光辅助对象
			scene.remove(cameraHelper);
		}
	}
);

watch(
	() => controlRef.value.target,
	(t) => {
		if(t === 'cube'){
			//平行光对准立方体
			directionalLight.target = cube;
		}else if(t === 'sphere'){
			//平行光对准球体
			directionalLight.target = sphere;
		}else{
			//平行光对准平面
			directionalLight.target = plane;
		}
	}
);

window.addEventListener('resize', () => {
	camera.aspect = window.innerWidth / window.innerHeight;
	camera.updateProjectionMatrix();
	renderer.setSize(window.innerWidth, window.innerHeight);
}, false);

onMounted(() => {
	statsRef.value?.append(stats.dom);
	containerRef.value?.appendChild(renderer.domElement);
	renderer.render(scene, camera);
});
</script>

<style scoped>
</style>